// Fibonacci B
// 
// Application which uses two processes and a shared file to facilitate inter process communication
// 
// Author: F.M.A. Erich
// HAN University of Applied Science
// Arnhem, The Netherlands

using System;
using System.Threading;
using Mono.Unix.Native;
using Mono.Unix;
using System.Diagnostics;
using System.IO;

namespace Producer
{
    class MainClass
    {
        public static void Main(string[] args)
        {
            CircularBuffer cb = new CircularBuffer(25);
            Producer p = new Producer(cb);
			Process.Start("mono Consumer.exe"); // Consumer.exe has to be in the same directory as Producer.exe
            p.produce();
        }
    }
	
    class CircularBuffer
    {
        string file = "pr.txt~";
        int fdin;
        public UnixStream us;
        private int size;

        // constructor for Circular Buffer takes argument size, which represents
        // the maximum amount of items which can be stored in this buffer
        public unsafe CircularBuffer(int size)
        {
            this.size = size;
            if((fdin = Syscall.open(file,  OpenFlags.O_RDWR|OpenFlags.O_TRUNC)) < 0) { // we want to start producing with an empty file
                Console.WriteLine ("fdin={0}", fdin);
                Syscall.perror ("open");
                return;
            }
            us = new UnixStream(fdin);
        }
		
        // Add an element to the buffer
        public void putElement(long element)
        {
            byte[] buffer = BitConverter.GetBytes(element); // streams only accept byte arrays
            us.Seek(0, SeekOrigin.End);
            us.Write(buffer, 0, sizeof(long));
        }

        // Returns the size of this buffer
        public int getSize()
        {
            return this.size;
        }
    }

    class Producer
    {
        private long lastFibonacci=0;
        private long currentFibonacci=1;
        private long nextFibonacci;
        private CircularBuffer cb;
		private static Mutex mut = new Mutex(false, "fibobmutex"); // named mutex so the consumer can open it

        public Producer(CircularBuffer cb)
        {
            this.cb = cb;
        }

        // Start producing fibonacci numbers
        public void produce()
        {
            Random RandomClass = new Random();
            int i=0;

            while(true)
            {
				mut.WaitOne();
                while (cb.us.Length < cb.getSize()*sizeof(long)) // Determine how much space is needed in the file per element 
                                                                 // and use that to see how many elements are currently in it
                {
                    i++;
                    Thread.Sleep(RandomClass.Next(0, 1000));     // sleep between 0 and 1 second
                    nextFibonacci = currentFibonacci + lastFibonacci;
                    Console.WriteLine("Fibo {0}: {1}", i, nextFibonacci);
                    cb.putElement(nextFibonacci);
                    lastFibonacci = currentFibonacci;
                    currentFibonacci = nextFibonacci;
                }
				mut.ReleaseMutex();
            }
        }
    }
}
